﻿#region License
/*
Copyright (c) 2009, Open University of the Netherlands
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided 
that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the 
  following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
  the following disclaimer in the documentation and/or other materials provided with the distribution.

* Neither the name of Open University of the Netherlands nor the names of its contributors may be 
  used to endorse or promote products derived from this software without specific prior written 
  permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/
#endregion

namespace EwbDesigner.NET
{
    using System;
    using XmlTreeNode = System.Collections.Generic.SimpleTreeNode<EwbDesigner.NET.XmlCacheItem>;
    using XsdTreeNode = System.Collections.Generic.SimpleTreeNode<EwbDesigner.NET.XsdCacheItem>;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Diagnostics;
    using System.Globalization;
    using System.IO;
    using System.Security.Permissions;
    using System.Threading;
    using System.Windows.Forms;
    using System.Windows.Forms.Design;
    using System.Xml;
    using System.Xml.Schema;

    using BrightIdeasSoftware;

    using Ionic.Zip;

    using EwbDesigner.NET.Classes;

    using WeifenLuo.WinFormsUI.Docking;
    using Microsoft.Win32;
    using EwbDesigner;
    using EwbDesigner.Classes;

    //dd-mm-yyyy - who - description
    //----------   ---   -------------------------------------------------------------------------------
    //28-07-2009 - veg - Moved BB Code temporarily into BlackBoard Export Script Delegate.
    //           - veg - Linked PropertyGrid back to the Attribute values.
    //           - veg - Added a 'edited' property to cache the tag/treenode beiing edited.
    //           - veg - Enabled display of changed values by setting both value and defaultvalue.
    //           - veg - Use ExecuteAndUnloadScript for Moodle export that allows it to be
    //                   executed more than once.
    //29-07-2009 - veg - Added custom types to PropertyGrid.
    //           - veg - Moved readonly attribute into new XsdAttributeFlags enum.
    //           - veg - Added custom type 'title' to the xsd and render it as a MultiLineEditor.
    //           - veg - Swapped Debug.* code for Trace.* code.
    //03-08-2009 - veg - Solved a nasty problem with the XsdAttributeItem by adding a Copy Constructor.
    //           - veg - Sorted sourcecode with NArrange.
    //05-08-2009 - veg - Managed to get the StringCollection to work (with the StringCollectionEditor
    //                   in the PropertyGrid.
    //11-08-2009 - veg - Upgraded to v2.5.0 of cs-script.
    //           - veg - Added a custom StringCollection Editor that converts silently between StringCollection and String.
    //14-08-2009 - veg - Added ObjectTreeListView and bound it to the XsdModel.
    //           - veg - Renamed some generic classes with using for better readability.
    //           - veg - Move some Xsd constructs to separate definition so they can be re-used.
    //           - veg - Added multiplicty column to ObjectTreeListView.
    //           - veg - Moved XsdCacheItem and XsdAttributeItem into seperate classes.
    //           - veg - Solved another nasty bug where the value of the editor wasn't set when equal
    //                   to the default value. Result of this optimalization was that the old value
    //                   could be preserved (propably the PropertyGrid isn't cleared correctly).
    //25-08-2009   veg - Started on integrating the TreeListView and remove TreeView code.
    //                 - Ported code that inserts at the correct place in the TreeListView.
    //                 - Ported code that removes TreeNodes from the XmlModel and TreeListVview.
    //26-09-2009   veg - Ported Xml Export and moved code into XmlTreeModel.
    //             veg - Fixed (again) the problem that we had copies of attributes. The XsdCacheItem's copy constructor
    //                   contained a flaw and did not copy attributes correctly.
    //                 - Moved Scripting code into ScriptHelper class.
    //                 - Made ScriptHelper class IDisposable.
    //                 - TreeListView now completly replaces the old TreeView.
    //                 - Extended ScriptHelper and resolve problems with multiple calls into a single piece of code.
    //09-09-2009   veg - Split XsdCacheItem & XsdAttributeItem into an Xsd and Xml class.
    //                 - Added NodeByValue to XmlTreeModel.
    //                 - Editor is now linked to both XsdModel (definition) and XmlModel (actual value)!
    //                 - Turned editing property into a XmlTreeNode so we have more control.
    //                 - Trimmed XmlTreeNode / XmlCacheItem implementation downto the neccesary.
    //10-09-2009   veg - Removed XsdDictonary.
    //                 - Added Generated Path (based on PathProperty and PathSeparator).
    //                   Added it to SimpleTreeNode and based it on Reflection!
    //                 - When addign Xml Nodes, pass the XsdTreeNode instead of a childNode. This way we
    //                   can check the Path where in the old code the Node would not belong to a Tree and Path
    //                   would fault.
    //                 - Removed Key and some other obsolete properties from Xsd/XmlCacheItem like
    //                   Collection, haschildren, key, GetChildren & Children, IsRoot, Parent and IsChildOf.
    //                   This code now works better because it is implemented already in the SimpleTree.
    //                 - Started on loading of XmlDocument instances.
    //                 - Added Xsd to Xml Instance.
    //                 - Added Simple DumpTree to Xml/XsdTreeModel.
    //22-09-2009   veg - Added zipping of Moodle Export
    //                 - Renamed Moodle Xml result to Moodle.xml (and not manifest.xml).
    //                 - Worked on date & boolean format in MoodleExport Script.
    //                 - Corrected export so it is imported into Moodle.
    //24-09-2009   veg - Added ExporedAs attributes to Xsd.
    //                 - Remodelled the Xsd by introducing Xsd includes.
    //                   The Xsd now contains single definitions of various (re-usable) objects.
    //                 - Switched PropertyGrid help to use the ExportAs value instead of the qualified datatype.
    //09-10-2009   veg - Move TreeListView delegates into the Structure(Docking)Form.
    //                 - Added Archive Viewer.
    //12-10-2009   veg - Added support for XSD Annotations. Added annotation attribbute to XsdCacheItem.
    //                   Sample:
    //                   <annotation>
    //                     <documentation xml:lang="en">
    //                      The documentation annotation type allows you to include basic
    //                      documentation within the XSD schema source.
    //                     </documentation>
    //                    </annotation>
    //                   Note: they are only supported in the main XSD and not the included ones.
    //                 - Added cleanup of course_files directory.
    //                 - Added file/directory icons to archive viewer.
    //16-10-2009   veg - Upgraded to latest DotNetZip and incorprated it into the build (removed all references
    //                   to the CF and KeyFile.
    //                 - Zip.AddStringAsFile() are obsoleted and replaced by AddEntry().
    //                 - ZipEntry LocalFileName is no longer supported so use FileName, change directory separators
    //                   and use Path.GetDirectorty on all of them to remove the trailing DirectorySeparatorChar.
    //20-10-2009   veg - Changed Exports so they zips to and return the zip file.
    //22-10-2009   veg - Converted the 4cid model to something that can be read.
    //                 - Started on documenting xsd features en structure.
    //27-10-2009   veg - Moved various code pieces to DockignForms.
    //                 - Fixed editing Title in 4cid model (Title attribute name is case-sensitive!).
    //28-10-2009   veg - To get scripts running again I needed to recalculate security perimssion
    //                   and MVS set it to full trust application again.
    //                 - Fixed TreeListView.SetObjects/RemoveObjects() giving an out-of-range exception by
    //                   using BeginUpdate & EndUpdate and just re-applying the collection with SetObjects().
    //                 - Fixed a but in ArchiveForm (see the previous remark) that would sometimes generated an exception.
    //                 - Fixed errors in BlackboardExport Script caused by importing the resources from the main
    //                   application. First added the application to the assemblies used by the script and
    //                   then changed the resource loading code a bit so it loads the main exe first.
    //                 - Changed 'Pim.NET' in 'Pim.xsd' into 'EWB' so it matches '4cid.xsd'.
    //                 - Added code to wipe *.dat files during Blackboard export.
    //02-11-2009   veg - Changed 4cid model so it resembles more what it was intented to do.
    //                 - Added a .ToString() instead of a (String) cast because Integers where not returned correct from the proprtygrid.
    //06-11-2009   veg - Added PreviewForm.
    //13-11-2009   veg - Added checkboxes for signalling optional items.
    //                 - Moved code to first column.
    //                 - Changed "Titel" to "titel"
    //                 - Made code column edititable and supplied it with a default value.
    //                 - Changed xsd to HHE's v1.1
    //                 - Removed extra code tags (changed group to attributeGroup).
    //                 - Do no longer sort attributes in PropertyGrid.
    //                 - Added a dummy Root element to Xsd and Xml so EWB (the toplevel tag) is its 
    //                   only child and shows up nicely. It's also exportable now (so we could move the 
    //                   prologue generation to it!
    //                 - Added 'Omhoog' and 'Omlaag' menuitems.
    //                 - Added code to enable 'Omhoog' and 'Omlaag' menuitems based on ischoice and 
    //                   multiplicity.
    //                 - Fixed insertion point of new taakklasses etc to be at the end and not at the start.
    //14-11-2009   veg - Added Swap to SimpleTree().
    //                 - Added Prev() and Next() to SimpleTreeList (Children Property).
    //                 - Added Checks on parent!=null in  SimpleTree Prev/Next/Index.
    //                 - Used v2.3 stable release of ObjectlistView.
    //16-11-2009   veg - Fixed display updates after swapping nodes. We need to update the parent with RefreshObject() and that 
    //                   will update the parent and its children correctly.
    //                 - Simplyfied insertion code in DoAddXmlModelNodes(). 
    //NOTE               Have to check what happens when we have an adjacent choice?
    //18-11-2009  veg  - Split editorflas into behaviour (flags) and type (enum). This makes it easier to identify an editor inside the PropertyGrid.
    //                 - Added a Panelmanager based UITypeEditor that can be used for editing restrictions, title and html.
    //NOTE             - The CheckedListBox control does only resize to the height of an integral sectionnumber of checkboxes.
    //                 - Upgraded the BlackBoard export so it now exports structure hierachical as it should.
    //                 - Adjusted the Psy model by Khaled so it works and exports to both Moodle and BlackBoard.
    //                 - Added TitleText (Content) and Title (Toc) export to BlackBoard.
    //                 - Added editor property to both XsdAttributeItem and XmlAttributeItem.
    //                 - Adjusted the code of the Wysiwyg dockpanel.
    //                 - Corrected zipping of BlackBoard export (stripped path from filename inside archive).
    //NOTE             - Have to look at the hardcoded 'tekst' attributes.
    //19-11-2009   veg - Changed attribute names to lowercase. 
    //NOTE             - Beware this might giove some problems.
    //                 - Gave presentation for projectgroup.
    //                 - Changed project name(space) from 'Pim' to 'EwbDesigner'.
    //20-11-2009   veg - Added more ExportedAs attributes to non Pimv2 Xsd's.
    //                 - Renamed 'title' attributes to 'tekst'
    //                 - Verified Pimv2 export is partially working 
    //                   (no toplevel nodes are exported into Moodle topic 0).
    //                 - Project now under versioncontrol at CodePlex with TeamFoundation.
    //                 - Changed Metadata export to Moodle so it skips ExportedAs.
    //                 - Fixed Course Title/Fullname (<EWB> code attribute) and ShortName (<EWB> code attribute).
    //21-11-2009   veg - Added MRU Menu code (See http://www.codeproject.com/KB/cs/mrutoolstripmenu.aspx).
    //                 - Added Annotations for attributes as well.
    //23-11-2009   veg - Added LogForm DockingForm for displaying logging instead of VS2008 IDE. 
    //                 - Added a LogListener for above. 
    //NOTE             - The LogListener works fine for the application but fails in the Export Scripts.
    //                 - Added rudementary XsdViewer showing elements and attributes in a single tree.
    //                 - Improved XsdViewer a bit.
    //                 - Added and debugged ExportAs_Html() for Moodle.
    //24-11-2009   veg - Debugged ExportAs_Resource (ie CreateResource) in MoodleExport.cs. 
    //26-11-2009   veg - Added complexiteit attribute as backup for studielast during export.
    //NOTE             - Actual files might be placed in a subdirectory so they do not show up directly.
    //28-11-2009   veg - Finally fixed the bug causing topic zero to be corrupted in Moodle. Cause was
    //                   a missing increment of the section counter, so there where at least two 
    //                   section zero's.
    //                 - Corrected all booleans in the Moodle Export to match an actual export.
    //                 - Added code to update the Summary of Section zero when the Ewb is exported.
    //01-12-2009   veg - Added automatic restore of the saved layout at startup.
    //                 - Fixed a bug in restoring the layout if any windows are visible.
    //                 - Adjusted the psy.xsd so it exports the thema & task correctly (also added studielast & code)
    //                 - Added xs:boolean to the supported datatypes.
    //                 - Fixed a bug in the MoodleExport where it did not write the correct number of sections into the moodle.xml.
    //NOTE             - Above still does not work correctly as Moodle does not overwite the value if a course is restored onto an 
    //                   existing one (it keeps the old numsections value).           
    //             kmz - Split Psy Model into a top level course and child metacourse ('studietaken').
    //02-12-2009   veg - Updated documentation on ewb.codeplex.com. 
    //             hhe - Incorporated some small xsd changes.
    //                   VERSION ON CODEPLEX
    //14-04-2010   veg - Fixed security errors in script calls (surfaced again in windows 7). Used a different way to compile
    //                   without the automatic dispose. 
    //                   Made both scripts clear the xml output as we now call the same assembly every time.
    //             veg - Same for deleting the moodle.xml.
    //             veg - Fixed a strange bug that caused the ArchiveForm to lock a file. 
    //                   Now before callign a script we clear the ArchiveForm.
    //             veg - Upgraded to cs-script 2.6 for DotNet 3.5.
    //             veg - Had a fight with Team Foundation at Codeplex.
    //----------   ---   -------------------------------------------------------------------------------
    //TO DO        hhe - Accelarators for switching between windows?
    //                 - Add more Annotations to xsd.
    //----------   ---   -------------------------------------------------------------------------------
    //TO DO        veg + Derive Base Exported Class.
    //
    //                 + After Export, use zipfile to extract the file needed to display as xml.
    //                 + Link archiveForm to XML viewer for displaying the selected node.
    //                 + Url fails in Moodle Export.
    //                 + Targetnamespace should be picked up from xsd...
    //
    //                 - Add author instructions to the XSD and export script.
    //                 * Escape Xhtml properly in export (copyright symbol for instance).
    //                 - Move parsing/dumping code to XsdModel class!!
    //                 - Add zipping of Resources (Bronnen/Instrumenten).
    //----------   ---   -------------------------------------------------------------------------------
    //NOTES        veg - Export Problems
    //----------   ---   -------------------------------------------------------------------------------
    /*
     *
        De Xsd's zijn opgebouwd uit een hoofdstructuur (te openen Xsd in de editor) en 
        een of meer ge-include xsd's met herbuikbare structuren.

        De boomvorminge EWB structuur definitie file include een 
        tweede schema dat herbruikbaare definities gevat van substructuren.

        **LET OP: de targetNamespace van alle xsd's moet 'pimv2' zijn.

        Een EWB bevat exact een root node met daaronder de structuur van het EWB.
  
            <?xml version="1.0" encoding="utf-8" ?>
            <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="pimv2" xmlns:xs="http://www.w3.org/2001/XMLSchema">
                <xs:element name="EWB">
                    ...
                </xs:element>
            </xs:schema>      
      
        Herbruikbare definities worden gecomponeerd mbv: 
            'simpleType', 
            'complexType', 
            'group' en 
            'attributeGroup' 
        elementen.

        Bij hergebruik dmv het 'type' of 'ref' attribuut moet de occurence gedefinieerd worden in deze file.

        De waarde van het 'minOccurs' attribuut mag groter zijn dan 0 zolang maar kleiner dan 'maxOccurs'.
        'maxOccurs' mag ook de waarde 'unbounded' bevatten.

        Referenties naar en typering van elementen wordt gedaan dmv een namespace definitie, bv:
          <xs:element xmlns:q1="pimv2" name="Introductie" type="q1:Introductie">.

        **LET OP: De element tag is niet toegestaan als toplevel node in deze include file en mag alleen gebruikt worden binnen een group of complexType!

        Attributen moeten voorzien zijn van een type attribuut. Toegestaane waarden zijn de standaard xmlschema types:

          1) xs:string
          2) xs:Name
          3) xs:int
          4) xs:float
          5) xs:double

        en de niet standaard types

          6) stringlist   (zorgt voor een lijst editor)
          7) title         (zorgt voor een multi-lne title editor)
          8) filename     (zorgt voor een browse file button)
          9) html         (zorgt voor een wysywig editor)

        Voorbeeld:

          <xs:attribute xmlns:q1="pimv2" name="tekst" type="x;string"/>
        of
          <xs:attribute xmlns:q1="pimv2" name="tekst" type="q1:html"/>
      
        Voor beinvloeding van de export kan een attribuut 'ExportedAs' opgenomen worden met een fixed value, die refereerd naar de methode in het script die voor de export gebruikt zal gaan worden. Bv:

          <xs:attribute xmlns:q1="pimv2" name="ExportedAs" type="xs:string" fixed="Task"/>

        zorgt er voor dat tijdens de export een functie:

          public static void ExportedAs_Tasks(XmlNode node)
     
        wordt aangeroepen. Is het attribuut er niet dan valt de export automatisch terug op een combinatie van 'ExportedAs_' en de 'Name' van het element.

        Attributen mogen 'default' of 'fixed' attribuut en value hebben. Als 'fixed' gebruikt wordt dan wordt het attribuut read-only getoond in de editor.

        Een 'titel' attribuut word in de tweede kolom van de structuur getoond, bv:

          <xs:attribute xmlns:q1="pimv2" name="titel" type="xs:string" default="Vul hier casus titel in" />

        Attribute order is (for readability/alignement) fixed like: 
            a) the namespace even if not neccesary, 
            b) name, 
            c) type and 
            d) fixed or default value. 
     
        so like:
            <xs:attribute xmlns:q1="pimv2" name="ExportedAs" type="xs:string" fixed="List" />     
       
      **LET OP: Aan elkaar grenzende choices kunnen mogelijk problemen geven bij het verplaatsten van elementen.
      **LET OP: ...
     */

    /// <summary>
    /// Design is that this form reads a XSD (XmlSchema) and stores information like multiplicty in the XsdModel. 
    /// This cache is used to generate a TreeLike structure of the Workbook.
    /// 
    /// The tree is used to generate an editor based on the PropertyGrid but with instaead of the normally assiociated 
    /// visible component a PropertyBag. The changes in the property editor are fed back into the XsdAttributeItem collection 
    /// being edited. Changed property values are shown in Bold.
    /// 
    /// When exported, the Tree and it'key properties are rendered into a Xml Document.
    /// The various exporters (External C# scripts) use this Xml Document to generate appropriate output for 
    /// Moodle and/or Blackboard.
    /// </summary>
    public partial class Form1 : Form
    {
        #region Fields

        private static Char[] ListSeparator = CultureInfo.CurrentCulture.TextInfo.ListSeparator.ToCharArray();

        private CpuUsage cpu = new CpuUsage();
        private DeserializeDockContent fDeserializeDockContent = null;

        //MRU COde
        private MruStripMenu mruMenu;
        static string mruRegKey = "SOFTWARE\\Open Universiteit Nederland\\EwbDesigner";

        //LogListener listener = new LogListener();

        #endregion Fields

        #region Constructors

        /// <summary>
        /// The Form constructor.
        /// </summary>
        public Form1()
        {
            InitializeComponent();

            Trace.AutoFlush = true;
            Trace.Listeners.Add(Program.listener);

            //Restore Docked Windows
            try
            {
                fDeserializeDockContent = new DeserializeDockContent(GetContentFromPersistString);
            }
            catch (Exception e)
            {
                //Problem loading EwbDesigner.NET.config
                Debug.WriteLine(e.Message);
            }

            instance = "";

            //Dialog Code
            openModelDialog.InitialDirectory = Application.StartupPath;
            openInstanceDialog.InitialDirectory = Application.StartupPath;
            saveInstanceDialog.InitialDirectory = Application.StartupPath;

            //Docking Form Code
            StructureForm.Instance.Show(dockPanel1);
            PropertiesForm.Instance.Show(dockPanel1);
            HelpForm.Instance.Show(dockPanel1);
            ArchiveForm.Instance.Show(dockPanel1);
            LogForm.Instance.Show(dockPanel1);

            StructureForm.Instance.DockTo(dockPanel1, DockStyle.Fill);
            PropertiesForm.Instance.DockTo(dockPanel1, DockStyle.Right);
            HelpForm.Instance.DockTo(dockPanel1, DockStyle.Right);
            ArchiveForm.Instance.DockTo(dockPanel1, DockStyle.Right);
            LogForm.Instance.DockTo(dockPanel1, DockStyle.Bottom);

            //Mru Code
            RegistryKey regKey = Registry.CurrentUser.OpenSubKey(mruRegKey);
            if (regKey != null)
            {
                menuClearRegistryOnExit.Checked = (int)regKey.GetValue("delSubkey", 0) != 0;

                regKey.Close();
            }

            mruMenu = new MruStripMenuInline(menuFile, menuRecentFile, new MruStripMenu.ClickedHandler(OnMruFile), mruRegKey + "\\MRU", 16);

            mruMenu.LoadFromRegistry();

            Debug.WriteLine("EwbDesigner started");
        }

        #endregion Constructors

        #region Properties

        /// <summary>
        /// Stores the resulting Xml instance of the Xsd Model.
        /// </summary>
        private String instance
        {
            get;
            set;
        }

        #endregion Properties

        #region Event Handlers

        private void BlackBoard_MenuItem_Click(object sender, EventArgs e)
        {
            StructureForm.Instance.Model = Path.Combine(Application.StartupPath, "4cid_v11.xsd");
            DoOpenModel(StructureForm.Instance.Model);
            DoSaveInstance(Path.Combine(Application.StartupPath, "instance.xml"));

            String zipfile = BlackbBoardExport.Execute(instance);

            XmlForm.Instance.webBrowser1.Url = new Uri("file:///" + Path.Combine(Path.GetDirectoryName(StructureForm.Instance.Model), "imsmanifest.xml"));

            ArchiveForm.Instance.Content = zipfile;
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            Debug.WriteLine("Form1.Closed");
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            //CloseAllDocuments();

            //Mru Code
            RegistryKey regKey = Registry.CurrentUser.CreateSubKey(mruRegKey);
            if (regKey != null)
            {
                regKey.SetValue("delSubkey", menuClearRegistryOnExit.Checked ? 1 : 0);
                regKey.Close();
            }

            if (menuClearRegistryOnExit.Checked)
            {
                regKey = Registry.CurrentUser;
                regKey.DeleteSubKey(mruRegKey + "\\MRU", false);
            }

            base.OnClosing(e);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            restoreLayoutToolStripMenuItem.PerformClick();

            timer1.Enabled = true;
        }

        private void Moodle_MenuItem_Click(object sender, EventArgs e)
        {
            StructureForm.Instance.Model = Path.Combine(Application.StartupPath, "4cid_v11.xsd");
            DoOpenModel(StructureForm.Instance.Model);
            DoSaveInstance(Path.Combine(Application.StartupPath, "instance.xml"));

            String zipfile = MoodleExport.Execute(instance);

            XmlForm.Instance.webBrowser1.Url = new Uri("file:///" + Path.Combine(Path.GetDirectoryName(StructureForm.Instance.Model), "moodle.xml"));

            ArchiveForm.Instance.Content = zipfile;
        }

        private void archiveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ViewOrClose(sender, ArchiveForm.Instance);
        }

        private void blackboardExportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DoSaveInstance(Path.Combine(Application.StartupPath, "instance.xml"));

            using (ScriptHelper sh = new ScriptHelper())
            {
                //sh.Resource = @"EwbDesigner.NET.Scripts.BlackboardExport.cs";
                sh.Filename = @"Scripts\BlackboardExport.cs";
                sh.DebugBuild = true;
                sh.Additional = new String[] { "Ionic.Zip" };

                ArchiveForm.Instance.Content = null;

                //This works without security problems
                sh.Compile("BB", File.ReadAllText(sh.Filename));
                String zipfile = sh.Invoke("BB", new Object[] { instance });
                sh.Remove("BB");

                //This fails with security problems
                //String zipfile = sh.Execute(new Object[] { instance });

                //TODO Let execute return the zip file and show an extracted copy imsmanifest.xml.
                XmlForm.Instance.webBrowser1.Url = new Uri("file:///" + Path.Combine(Path.GetDirectoryName(StructureForm.Instance.Model), "imsmanifest.xml"));

                ArchiveForm.Instance.Content = zipfile;
            }
        }

        private void contentToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ViewOrClose(sender, WysiwygForm.Instance);
        }

        /// <summary>
        /// Quit the application
        /// </summary>
        /// <param name="sender">-</param>
        /// <param name="e">-</param>
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void helpToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ViewOrClose(sender, HelpForm.Instance);
        }

        private void loadInstanceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openInstanceDialog.ShowDialog() == DialogResult.OK)
            {
                //TODO Extract and set model...
                Data.XmlModel.fromXml(openInstanceDialog.FileName);

                //Add RootNodes (and its mandatory offspring by recursion).
                StructureForm.Collection = Data.XmlModel.Root.Children;
                StructureForm.Structure.ExpandAll();
            }
        }

        private void moodleExportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DoSaveInstance(Path.Combine(Application.StartupPath, "instance.xml"));

            using (ScriptHelper sh = new ScriptHelper())
            {
                sh.Filename = @"Scripts\MoodleExport.cs";
                sh.DebugBuild = true;
                sh.Additional = new String[] { "Ionic.Zip" };

                //FileIOPermission filePerm = new FileIOPermission(FileIOPermissionAccess.Read, Path.Combine(Application.StartupPath, "CSScriptLibrary.dll"));
                //filePerm.Assert();

                ArchiveForm.Instance.Content = null;

                //This works without security problems.
                sh.Compile("Moodle", File.ReadAllText(sh.Filename));
                String zipfile = sh.Invoke("Moodle", new Object[] { instance });
                sh.Remove("Moodle");

                //This fails without security problems.
                //String zipfile = sh.Execute(new Object[] { instance }, true);

                //TODO Let execute return the zip file and show an extracted copy moodle.xml.
                XmlForm.Instance.webBrowser1.Url = new Uri("file:///" + Path.Combine(Path.GetDirectoryName(StructureForm.Instance.Model), "moodle.xml"));

                ArchiveForm.Instance.Content = zipfile;
            }
        }

        /// <summary>
        /// Open a Model.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void openModelToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (DoOpenModel())
            {
                DoUpdateMenus();

                Data.XsdModel.DumpTree();
            }
        }

        private void previewToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ViewOrClose(sender, PrintPreviewForm.Instance);
        }

        private void propertiesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ViewOrClose(sender, PropertiesForm.Instance);
        }

        private void restoreLayoutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //Note: Wrong Path for Vista!
            string configFile = Path.ChangeExtension(Application.ExecutablePath, ".config");

            if (File.Exists(configFile))
            {
                CloseAllDocuments();

                dockPanel1.LoadFromXml(configFile, fDeserializeDockContent);
            }
        }

        /// <summary>
        /// Create a XmlDocument 
        /// Save it to disk
        /// Show it in the WebBrowser.
        /// </summary>
        /// <param name="sender">-</param>
        /// <param name="e">-</param>
        private void saveInstanceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (saveInstanceDialog.ShowDialog() == DialogResult.OK)
            {
                DoSaveInstance(saveInstanceDialog.FileName);

                DoUpdateMenus();
            }
        }

        private void saveLayoutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //Note: Wrong Path for Vista!
            string configFile = Path.ChangeExtension(Application.ExecutablePath, ".config");

            dockPanel1.SaveAsXml(configFile);
        }

        private void structureToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ViewOrClose(sender, StructureForm.Instance);
        }

        private void testExportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (ScriptHelper sh = new ScriptHelper())
            {
                sh.Filename = @"Scripts\TestExport.cs";
                sh.DebugBuild = true;
                sh.Additional = new String[] { "Ionic.Zip" };

                //ArchiveForm.Instance.Content = null;

                sh.Compile("test", File.ReadAllText(sh.Filename));
                sh.Invoke("test", new Object[] { "test" });

                //ArchiveForm.Instance.Content = zipfile;
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            short usage = cpu.GetUsage();

            if (usage >= 0 && usage <= 100)
            {
                toolStripProgressBar1.Value = (Int32)usage;
            }

            //Debug.WriteLine(cpu.GetUsage().ToString() + "%");
        }

        private void viewToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            structureToolStripMenuItem.Checked = !(StructureForm.Instance.DockState == DockState.Hidden || StructureForm.Instance.DockState == DockState.Unknown);
            propertiesToolStripMenuItem.Checked = !(PropertiesForm.Instance.DockState == DockState.Hidden || PropertiesForm.Instance.DockState == DockState.Unknown);
            xmlToolStripMenuItem.Checked = !(XmlForm.Instance.DockState == DockState.Hidden || XmlForm.Instance.DockState == DockState.Unknown);
            helpToolStripMenuItem.Checked = !(HelpForm.Instance.DockState == DockState.Hidden || HelpForm.Instance.DockState == DockState.Unknown);
            archiveToolStripMenuItem.Checked = !(ArchiveForm.Instance.DockState == DockState.Hidden || ArchiveForm.Instance.DockState == DockState.Unknown);
            wysiwygToolStripMenuItem.Checked = !(WysiwygForm.Instance.DockState == DockState.Hidden || WysiwygForm.Instance.DockState == DockState.Unknown);
            printPreviewToolStripMenuItem.Checked = !(PrintPreviewForm.Instance.DockState == DockState.Hidden || PrintPreviewForm.Instance.DockState == DockState.Unknown);
            logToolStripMenuItem.Checked = !(LogForm.Instance.DockState == DockState.Hidden || LogForm.Instance.DockState == DockState.Unknown);
            xsdToolStripMenuItem.Checked = !(XsdForm.Instance.DockState == DockState.Hidden || XsdForm.Instance.DockState == DockState.Unknown);
        }

        private void xmlToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ViewOrClose(sender, XmlForm.Instance);
        }

        private void OnMruFile(int number, String filename)
        {
            if (File.Exists(filename))
            {
                DoOpenModel(filename);
            }
            else
            {
                DialogResult result = MessageBox.Show(
                             "Het bestand:\n\n'" + filename
                             + "'\n\nkan niet geopend worden\n\n"
                             + "Dit bestand verwijderen uit de MRU lijst?"
                             , "EwbDesigner"
                             , MessageBoxButtons.YesNo);

                if (result == DialogResult.Yes)
                {
                    mruMenu.RemoveFile(number);
                    mruMenu.SaveToRegistry();
                }
            }
        }

        private void Form1_Shown(object sender, EventArgs e)
        {
            ArchiveForm.Instance.Content = "moodle_backup.zip";
        }

        private void menuSettingsClearRegOnExit_Click(object sender, EventArgs e)
        {
            menuClearRegistryOnExit.Checked = !menuClearRegistryOnExit.Checked;

            RegistryKey regKey = Registry.CurrentUser.OpenSubKey(mruRegKey, true);
            if (regKey != null)
            {
                regKey.SetValue("delSubkey", menuClearRegistryOnExit.Checked ? 1 : 0);
                regKey.Close();
            }

        }

        private void clearMRUToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RegistryKey regKey = Registry.CurrentUser;
            regKey.DeleteSubKey(mruRegKey + "\\MRU", false);
        }

        private void logToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ViewOrClose(sender, LogForm.Instance);
        }

        private void xsdToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ViewOrClose(sender, XsdForm.Instance);
        }

        #endregion Event Handlers

        #region Methods

        public void StatusBarText(String Text)
        {
            toolStripStatusLabel1.Text = Text;
        }

        public void StatusBarText(String format, params object[] args)
        {
            StatusBarText(String.Format(format, args));
        }

        /// <summary>
        /// Close All (Docking) Documents.
        /// </summary>
        private void CloseAllDocuments()
        {
            dockPanel1.Contents.RemoveAll();
        }

        /// <summary>
        /// Dump XSD to console.
        /// </summary>
        /// <param name="schema">the XmlSchema to dump</param>
        /// <returns>Xml</returns>
        private string DebugDumpSchema(XmlSchema schema)
        {
            using (StringWriter ms = new StringWriter())
            {
                try
                {
                    schema.Write(ms); //Throws FileNotFoundException.
                }
                catch (Exception e)
                {
                    Trace.Fail(e.GetType().Name, e.Message);
                }
                return ms.ToString();
            }
        }

        /// <summary>
        /// Remove a Node and its offspring from the TreeView.
        /// </summary>
        /// <param name="tn">The TreeNode to remove.</param>
        private void DoDeleteTreeNodes(XmlTreeNode xtn)
        {
            if (xtn.Parent != null)
            {
                XmlTreeNode p = (XmlTreeNode)xtn.Parent;

                p.Children.Remove(xtn);

                StructureForm.Structure.RefreshObject(p);
            }
            else
            {
                Data.XmlModel.Root.Value = null;

                StructureForm.Structure.ClearObjects();
            }
        }

        /// <summary>
        /// Parse a XSD Schema with SOM (Schema Object Model).
        /// Build the Occurences Cache.
        /// Build the Add MenuItem'key SubMenu.
        /// Add all RootNodes recursively to the main TreeView (Add only the mandatory nodes).
        /// </summary>
        private Boolean DoOpenModel()
        {
            if (openModelDialog.ShowDialog() == DialogResult.OK)
            {
                DoOpenModel(openModelDialog.FileName);

                return true;
            }
            return false;
        }

        private void DoOpenModel(String model)
        {
            instance = Path.Combine(Path.GetDirectoryName(model), "Instance.xml");

            //Veg: Disabled for now!
            //if (File.Exists(instance))
            //{
            //    File.Delete(instance);
            //}

            openInstanceDialog.FileName = instance;
            saveInstanceDialog.FileName = instance;

            Text = "PimDotNet - " + Path.GetFileName(model);

            StructureForm.Instance.Model = model;

            XmlForm.Instance.Xml.Url = new Uri("file:///" + model);

            mruMenu.AddFile(model);
            mruMenu.SetFirstFile(mruMenu.FindFilenameNumber(model));
            mruMenu.SaveToRegistry();

            XsdForm.Collection = Data.XsdModel;

            DoUpdateMenus();
        }

        private void DoSaveInstance(String instance)
        {
            Data.XmlModel.ToXml(instance, StructureForm.Instance.Model);

            XmlForm.Instance.Show(dockPanel1);
            XmlForm.Instance.webBrowser1.Url = new Uri("file:///" + saveInstanceDialog.FileName);

            DoUpdateMenus();
        }

        private void DoUpdateMenus()
        {
            saveInstanceToolStripMenuItem.Enabled = File.Exists(StructureForm.Instance.Model);
            loadInstanceToolStripMenuItem.Enabled = File.Exists(StructureForm.Instance.Model);
            //veg: Instance now generated by export menuitems.
            moodleExportToolStripMenuItem.Enabled = File.Exists(StructureForm.Instance.Model) /*&& File.Exists(instance)*/;
            blackboardExportToolStripMenuItem.Enabled = File.Exists(StructureForm.Instance.Model) /*&& File.Exists(instance)*/;
        }

        /// <summary>
        /// Returns Instances of the requested DockingForms.
        /// </summary>
        /// <param name="persistString">The Type to Instantiate</param>
        /// <returns>A Dockable Form.</returns>
        private IDockContent GetContentFromPersistString(string persistString)
        {
            if (persistString == typeof(PropertiesForm).ToString())
            {
                return PropertiesForm.Instance;
            }
            else if (persistString == typeof(StructureForm).ToString())
            {
                return StructureForm.Instance;
            }
            else if (persistString == typeof(XmlForm).ToString())
            {
                return XmlForm.Instance;
            }
            else if (persistString == typeof(HelpForm).ToString())
            {
                return HelpForm.Instance;
            }
            else if (persistString == typeof(LogForm).ToString())
            {
                return LogForm.Instance;
            }
            else if (persistString == typeof(ArchiveForm).ToString())
            {
                return ArchiveForm.Instance;
            }
            else if (persistString == typeof(PrintPreviewForm).ToString())
            {
                return PrintPreviewForm.Instance;
            }
            else if (persistString == typeof(XsdForm).ToString())
            {
                return XsdForm.Instance;
            }
            else if (persistString == typeof(WysiwygForm).ToString())
            {
                return WysiwygForm.Instance;
            }

            return null;
        }

        private void ViewOrClose(object sender, DockContent content)
        {
            if ((sender is ToolStripMenuItem) && ((ToolStripMenuItem)sender).Checked)
            {
                content.DockState = DockState.Hidden;
            }
            else
            {
                //Show if never shown/docked before.
                if (content.DockPanel == null)
                {
                    content.Show(dockPanel1);
                }

                //VisibleState is the last known state other then unknown/hidden,
                //so either try to restore it or dock to the active window.
                if (content.VisibleState == DockState.Unknown)
                {
                    content.DockState = dockPanel1.ActivePane.DockState;
                }
                else
                {
                    Debug.Assert(content.VisibleState != DockState.Hidden, "DockState is Hidden, Cannot Restore!");

                    content.DockState = content.VisibleState;
                }

                //Activate the newly shown dockcontent.
                content.Activate();
            }
        }

        #endregion Methods

        public static void AddLogMsg(string msg)
        {
            LogForm.Instance.AddLogMsg(msg);
        }
    }
}
